package com.code;

import java.lang.reflect.Field;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class Decode {
	private String protocalName = "2.24";

	private CollectData decode(CollectData collectData) {
		decodeHeadPart224(collectData);
		decodeDataPart224(collectData);
		collectData.setDtime(new Date());
		return collectData;
	}

	private void decodeHeadPart224(CollectData collectData) {
		int target = Integer.parseInt(collectData.getScode().substring(6, 10), 16);
		collectData.setTargetStation(target >> 6);
		collectData.setTargetGroup(target & 0x003F);
		int source = Integer.parseInt(collectData.getScode().substring(10, 14), 16);
		collectData.setSourceStation(source >> 6);
		collectData.setSourceGroup(source & 0x003F);
		int router = Integer.parseInt(collectData.getScode().substring(14, 18), 16);
		collectData.setRouter(router >> 6);
		collectData.setRouterGroup(router & 0x003F);
		int index = Integer.parseInt(collectData.getScode().substring(18, 22), 16);
		collectData.setIndex(index);
		collectData.setData(collectData.getScode().substring(22,
				22 + Integer.parseInt(collectData.getScode().substring(4, 6), 16) * 2));

	}

	private void decodeDataPart224(CollectData collectData) {
		int dtype = Integer.parseInt(collectData.getData().substring(0, 2), 16);
		collectData.setDtype(dtype);
		int project = Integer.parseInt(collectData.getData().substring(2, 4), 16);
		collectData.setProject(project);
		int ecode = Integer.parseInt(collectData.getData().substring(4, 8), 16);
		collectData.setEcode(ecode);
		try {
			switch (dtype) {
			case 0x12:
				decodePhysicsParams224(collectData);
				break;
			case 0x81:
				decodePhysicsParams224(collectData);
				break;
			case 0x82:
				decodePhysicsParams224(collectData);
				decodeStatusParams224(collectData);
				break;
			case 0x83:
				decodePropertyParams224(collectData);
				break;
			case 0x84:
				decodeMessageParams224(collectData);
				break;
			case 0x85:
				decodeMessageParams224(collectData);
				break;
			case 0x86:
				decodePhysicsParams224(collectData);
				break;
			case 0x87:
				decodeMessageParams224(collectData);
				break;
			case 0x88:
				decodePhysicsParams224(collectData);
				break;
			case 0x89:
				decodePhysicsParams224(collectData);
				break;
			case 0x8A:
				decodeEntityParams224(collectData);
				break;
			case 0x8B:
				decodePhysicsParams224(collectData);
				break;
			case 0x8C:
				/* decodeComplexParams224(collectData); */break;
			case 0x01:
			case 0x02:
			case 0x03:
			case 0x04:
			case 0x06:
			case 0x0A:
			case 0x31:
			case 0x32:
			case 0x33:
			case 0x34:
			case 0x60: {
				collectData.setState("命令原码");
				collectData.setResult(String.format("%s中类型编码[%d]为命令类型", protocalName, dtype));
				return;
			}
			default: {
				collectData.setState("解码失败");
				collectData.setResult(String.format("%s无法解析数据类型[%d]", protocalName, dtype));
				return;
			}
			}
		} catch (StringIndexOutOfBoundsException e) {
			e.printStackTrace();
			collectData.setState("解码失败");
			collectData.setResult(String.format("参数数据长度与%s不一致无法解析数据类型[%d]", protocalName, dtype));
			return;
		} catch (Exception e) {
			e.printStackTrace();
			collectData.setState("解码失败");
			collectData.setResult(String.format("参数数据内容与%s不一致无法解析数据类型[%d]", protocalName, dtype));
			return;
		}
	}

	private void decodeEntityParams224(CollectData collectData) throws Exception {
		int offset = 8;
		int pcode;
		List<CollectParam> collectParams = new ArrayList<CollectParam>();
		CollectParam collectParam;

		PropertyDefinition pd = JsonToJavabean.publicTypeParamByCode(1);
		if (pd == null) {
			collectData.setState("解码失败");
			collectData.setResult("无法知识查询器中取得公共参数定义[大类编码]");
			return;
		}
		pcode = Integer.parseInt(collectData.getData().substring(offset, offset += 2), 16);
		if (pcode != 1) {
			collectData.setState("解码失败");
			collectData.setResult(String.format("%s要求对象包以大小类编码作为开头", protocalName));
			return;
		}
		collectParam = new CollectParam();
		collectParam.setPcode(pcode);
		collectParam.setPname(pd.getName());
		collectParam.setPdata(collectData.getData().substring(offset, offset += (pd.getDataLength() * 2)));
		setPvalue(pd.getVtype(), collectParam, pd.getDataLength());
		collectParams.add(collectParam);

		pd = JsonToJavabean.publicTypeParamByCode(2);
		if (pd == null) {
			collectData.setState("解码失败");
			collectData.setResult("无法从知识查询器中取得公共参数定义[小类编码]");
			return;
		}
		pcode = Integer.parseInt(collectData.getData().substring(offset, offset += 2), 16);
		if (pcode != 2) {
			collectData.setState("解码失败");
			collectData.setResult(String.format("%s要求对象包以大小类编码作为开头", protocalName));
			return;
		}
		collectParam = new CollectParam();
		collectParam.setPcode(pcode);
		collectParam.setPname(pd.getName());
		collectParam.setPdata(collectData.getData().substring(offset, offset += (pd.getDataLength() * 2)));
		setPvalue(pd.getVtype(), collectParam, pd.getDataLength());

		collectParams.add(collectParam);

		pd = JsonToJavabean.publicTypeParamByCode(3);
		if (pd == null) {
			collectData.setState("解码失败");
			collectData.setResult("无法从知识查询器中取得公共参数定义[父对象编码]");
			return;
		}
		pcode = Integer.parseInt(collectData.getData().substring(offset, offset += 2), 16);
		if (pcode != 3) {
			collectData.setState("解码失败");
			collectData.setResult(String.format("%s要求对象包以父对象及角色编码作为结尾", protocalName));
			return;
		}

		collectParam = new CollectParam();
		collectParam.setPcode(pcode);
		collectParam.setPname(pd.getName());
		collectParam.setPdata(collectData.getData().substring(offset, offset += (pd.getDataLength() * 2)));
		setPvalue(pd.getVtype(), collectParam, pd.getDataLength());
		collectParams.add(collectParam);

		pd = JsonToJavabean.publicTypeParamByCode(4);
		if (pd == null) {
			collectData.setState("解码失败");
			collectData.setResult("无法从知识查询器中取得公共参数定义[角色编码]");
			return;
		}
		pcode = Integer.parseInt(collectData.getData().substring(offset, offset += 2), 16);
		if (pcode != 4) {
			collectData.setState("解码失败");
			collectData.setResult(String.format("%s要求对象包以父对象及角色编码作为结尾", protocalName));
			return;
		}

		collectParam = new CollectParam();
		collectParam.setPcode(pcode);
		collectParam.setPname(pd.getName());
		collectParam.setPdata(collectData.getData().substring(offset, offset += (pd.getDataLength() * 2)));
		setPvalue(pd.getVtype(), collectParam, pd.getDataLength());
		collectParams.add(collectParam);

		collectData.setCollectParams(collectParams);
		EntityType et = JsonToJavabean.entityTypeByCode(Integer.parseInt(collectParams.get(0).getPvalue()),
				Integer.parseInt(collectParams.get(1).getPvalue()));
		if (et == null) {
			collectData.setState("解码失败");
			collectData.setResult(String.format("无法从知识查询器中取得大类编码为[%s]，小类编码为[%s]的对象类型", collectParams.get(0).getPvalue(),
					collectParams.get(1).getPvalue()));
			return;
		}
		collectData.setMname(et.getMname());
		collectData.setTname(et.getName());
	}

	private void decodeStatusParams224(CollectData collectData) {
		if (isEntityStatus(collectData)) {
			for (CollectParam collectParam : collectData.getCollectParams()) {

				if ("设备状态".equals(collectParam.getPname())) {
					collectParam.setPvalue("00".equals(collectParam.getPdata()) ? "正常" : "异常");
				}
			}
		}
	}

	private boolean isEntityStatus(CollectData collectData) {
		for (CollectParam collectParam : collectData.getCollectParams()) {
			if ("设备状态".equals(collectParam.getPname()))
				return true;
		}
		return false;
	}

	private void decodeMessageParams224(CollectData collectData) {
		int offset = 8;
		int length = collectData.getData().length();
		int pcode;
		PropertyDefinition pd;
		List<CollectParam> collectParams = new ArrayList<CollectParam>();
		CollectParam collectParam;
		while (offset < length) {
			pcode = Integer.parseInt(collectData.getData().substring(offset, offset += 2), 16);
			pd = JsonToJavabean.messageParamByCode(pcode);

			if (pd == null) {
				collectData.setState("解码失败");
				collectData.setResult(String.format("%s无法解析返回消息编码[%d]", protocalName, pcode));
				break;
			}
			collectParam = new CollectParam();
			if (pd.getDataLength() == 0) {
				collectParam.setPcode(pcode);
				collectParam.setPname("消息编码" + pcode);
				collectParam.setPvalue(pd.getName());
			} else {
				collectParam.setPcode(pcode);
				collectParam.setPname(pd.getName());
				try {
					collectParam.setPdata(collectData.getData().substring(offset, offset += (pd.getDataLength() * 2)));
					setPvalue(pd.getVtype(), collectParam, pd.getDataLength());
					collectParam.setUnit(pd.getUnit());
				} catch (Exception e) {
					collectData.setState("解码失败");
					collectData
							.setResult(String.format("在224协议中[%s]不是有效的[%s]数据", collectParam.getPdata(), pd.getName()));
					break;
				}
			}
			collectParams.add(collectParam);
		}
		collectData.setCollectParams(collectParams);

	}

	private void decodePhysicsParams224(CollectData collectData) throws Exception {
		int offset = 8;
		int length = collectData.getData().length();
		int pcode;
		MonitorItem monitorItem;
		List<CollectParam> collectParams = new ArrayList<CollectParam>();
		CollectParam collectParam;
		String pvalue;
		while (offset < length) {
			pcode = Integer.parseInt(collectData.getData().substring(offset, offset += 2), 16);
			monitorItem = JsonToJavabean.monitorItemByCode(pcode);
			if (monitorItem == null) {
				collectData.setState("解码失败");
				collectData.setResult(String.format("%s无法解析物理量编码[%d]", protocalName, pcode));
				break;
			}

			collectParam = new CollectParam();
			collectParam.setPcode(pcode);
			collectParam.setPname(monitorItem.getName());
			collectParam.setPdata(collectData.getData().substring(offset, offset += (monitorItem.getDataLength() * 2)));
			pvalue = getMonitorItemValue(monitorItem, collectParam.getPdata());
			collectParam.setPvalue(pvalue);
			collectParam.setUnit(monitorItem.getUnit());
			collectParams.add(collectParam);
		}
		collectData.setCollectParams(collectParams);
	}

	private String getMonitorItemValue(MonitorItem monitorItem, String tempValue) throws ParseException {
		String value;
		Field[] fields = monitorItem.getClass().getDeclaredFields();
		boolean b = false;
		for (Field field : fields) {
			if (field.getName().equals("decimalLength")) {
				b = true;
				break;
			}
		}
		if (monitorItem.getCode() == 244) {
			value = PropertyBuilder.DatetimeBuilder.decode(tempValue, monitorItem.getDataLength());
		} else if (monitorItem.getName().equals("数字信号")) {
			value = tempValue;
		} else if (b) {
			value = PropertyBuilder.FloatBuilder.decode(tempValue, monitorItem.getDataLength());
		} else {
			value = PropertyBuilder.IntegerBuilder.decode(tempValue, monitorItem.getDataLength());
		}
		return value;
	}

	private void decodePropertyParams224(CollectData collectData) throws Exception {
		int pcode = Integer.parseInt(collectData.getData().substring(8, 10), 16);
		if (pcode == 1) {
			decodeTypePropertyParams224(collectData);
		} else {
			decodeFreePropertyParams224(collectData);
		}
	}

	private void decodeTypePropertyParams224(CollectData collectData) throws Exception {
		int offset = 8;
		int length = collectData.getData().length();
		int pcode;
		List<CollectParam> collectParams = new ArrayList<CollectParam>();
		CollectParam collectParam;

		PropertyDefinition pd = JsonToJavabean.publicTypeParamByCode(1);
		if (pd == null) {
			collectData.setState("解码失败");
			collectData.setResult("无法知识查询器中取得公共参数定义[大类编码]");
			return;
		}
		pcode = Integer.parseInt(collectData.getData().substring(offset, offset += 2), 16);
		if (pcode != 1) {
			collectData.setState("解码失败");
			collectData.setResult(String.format("%s要求参数包以大小类编码作为开头", protocalName));
			return;
		}
		collectParam = new CollectParam();
		collectParam.setPcode(pcode);
		collectParam.setPname(pd.getName());
		collectParam.setPdata(collectData.getData().substring(offset, offset += (pd.getDataLength() * 2)));
		setPvalue(pd.getVtype(), collectParam, pd.getDataLength());
		collectParams.add(collectParam);

		pd = JsonToJavabean.publicTypeParamByCode(2);
		if (pd == null) {
			collectData.setState("解码失败");
			collectData.setResult("无法从知识查询器中取得公共参数定义[小类编码]");
			return;
		}
		pcode = Integer.parseInt(collectData.getData().substring(offset, offset += 2), 16);
		if (pcode != 2) {
			collectData.setState("解码失败");
			collectData.setResult(String.format("%s要求参数包以大小类编码作为开头", protocalName));
			return;
		}
		collectParam = new CollectParam();
		collectParam.setPcode(pcode);
		collectParam.setPname(pd.getName());
		collectParam.setPdata(collectData.getData().substring(offset, offset += (pd.getDataLength() * 2)));
		setPvalue(pd.getVtype(), collectParam, pd.getDataLength());
		collectParams.add(collectParam);

		EntityType et = JsonToJavabean.entityTypeByCode(Integer.parseInt(collectParams.get(0).getPvalue()),
				Integer.parseInt(collectParams.get(1).getPvalue()));
		if (et == null) {
			collectData.setState("解码失败");
			collectData.setResult(String.format("无法从知识查询器中取得大类编码为[%s]，小类编码为[%s]的对象类型", collectParams.get(0).getPvalue(),
					collectParams.get(1).getPvalue()));
			return;
		}
		collectData.setMname(et.getMname());
		collectData.setTname(et.getName());
		while (offset < length) {
			pcode = Integer.parseInt(collectData.getData().substring(offset, offset += 2), 16);

			pd = JsonToJavabean.getPropertyDefinition(et, pcode);
			if (pd == null) {
				collectData.setState("解码失败");
				collectData.setResult(String.format("无法从知识查询器中取得大类编码为[%s]，小类编码为[%s]的对象类型[%s]中未定义编码为[%d]的参数定义",
						collectParams.get(0).getPvalue(), collectParams.get(1).getPvalue(), et.getName(), pcode));
				break;
			}
			collectParam = new CollectParam();
			collectParam.setPcode(pcode);
			collectParam.setPname(pd.getName());
			collectParam.setPdata(collectData.getData().substring(offset, offset += (pd.getDataLength() * 2)));
			setPvalue(pd.getVtype(), collectParam, pd.getDataLength());
			collectParam.setUnit(pd.getUnit());
			collectParams.add(collectParam);
		}
		collectData.setCollectParams(collectParams);
	}

	private void decodeFreePropertyParams224(CollectData collectData) throws Exception {
		int offset = 8;
		int length = collectData.getData().length();
		int pcode;
		List<CollectParam> collectParams = new ArrayList<CollectParam>();
		CollectParam collectParam;
		PropertyDefinition pd = JsonToJavabean.publicTypeParamByCode(1);

		while (offset < length) {
			pcode = Integer.parseInt(collectData.getData().substring(offset, offset += 2), 16);

			pd = JsonToJavabean.publicTypeParamByCode(pcode);
			if (pd == null) {
				collectData.setState("解码失败");

				collectData.setResult(String.format("无法从知识查询器中取得编码为[%d]的公共参数", pcode));
				break;
			}

			collectParam = new CollectParam();
			collectParam.setPcode(pcode);
			collectParam.setPname(pd.getName());
			collectParam.setPdata(collectData.getData().substring(offset, offset += (pd.getDataLength() * 2)));
			setPvalue(pd.getVtype(), collectParam, pd.getDataLength());
			collectParam.setUnit(pd.getUnit());
			collectParams.add(collectParam);
		}
		collectData.setCollectParams(collectParams);
	}

	private void setPvalue(String type, CollectParam collectParam, int dataLength) throws Exception {
		String tempValue = collectParam.getPdata();
		// 参数值解码
		switch (type) {
		case "integer":
			collectParam.setPvalue(PropertyBuilder.IntegerBuilder.decode(tempValue, dataLength));
			break;
		case "double":
			collectParam.setPvalue(PropertyBuilder.FloatBuilder.decode(tempValue, dataLength));
			break;
		case "boolean":
			collectParam.setPvalue(PropertyBuilder.BooleanBuilder.decode(tempValue, dataLength));
			break;
		case "string":
			collectParam.setPvalue(PropertyBuilder.AscBuilder.decode(tempValue, dataLength));
			break;
		case "time":
			collectParam.setPvalue(PropertyBuilder.TimeBuilder.decode(tempValue, dataLength));
			break;
		case "datetime":
			collectParam.setPvalue(PropertyBuilder.DatetimeBuilder.decode(tempValue, dataLength));
			break;
		default: {
			collectParam.setPvalue(tempValue);
		}
		}
	}



	public static void main(String[] args) {
		Decode decode = new Decode();
		CollectData collectData = new CollectData();
		collectData.setMcode(12);
		collectData.setTcode(8);
		//collectData.setScode("EB9512004111810000000083420383010C0208110000000012000000007D0008EFB5");property
		//collectData.setScode("EB951300411181000000008842FFFECA4156F91AC841F228F6C9423A3DF3F619BA504E");physics
		//collectData.setScode("EB950500411181000000008442FFFE130A0201C46D");message
		//collectData.setScode("EB950D00411181000000008A42FFFD0108020103FFFE0403DFFFE9B3CC");entity
		//collectData.setScode("EB951A004111810000750B8242FFFEF4190802090800CA4156F109C841F08F5AC942267865700AA204D7");status
		collectData.setScode("EB950D004111810000750A82420002F4190802090800CE00FDD3312FF4");
		decode.decode(collectData);
	}
}
